import importlib
import inspect
import numbers
import re
from pathlib import Path

def bfloat(s):
    """将带单位的字符串转换为浮点数"""
    if isinstance(s, numbers.Number):
        return s
    elif isinstance(s, str):
        # 去除前后空格
        s = s.strip()
        # 使用正则表达式匹配数字（包括小数）
        finds = re.findall('-?\d+(?:\.\d+)?', s)
        if finds:
            # 提取匹配到的数字字符串
            num_str = finds[0]
            # 处理特殊格式（如.22m转换为0.22）
            # if num_str.startswith('.'):
            #     num_str = '0' + num_str
            try:
                return float(num_str)
            except ValueError:
                raise ValueError(f"无法将 '{s}' 转换为有效数字\n")
        else:
            raise ValueError(f"字符串 '{s}' 中未找到有效数字\n")
    else:
        raise ValueError(f"未知输入 '{s}'\n")

# 数字格式化
def bfloats(*args):
    return map(bfloat, args)

# 路径转换
def bpath(path):
    """
    如果 path 是绝对路径，则直接返回；如果是相对路径，则将其转换为绝对路径后返回。

    参数:
        path (str): 输入的路径。

    返回:
        str: 绝对路径。
    """
    # current_dir = os.path.dirname(os.path.abspath(__file__))
    # 构建模块的绝对路径
    # module_path = os.path.join(current_dir, '../utils', f'{module_name}.py')
    path = Path(path)
    if path.is_absolute():
        return str(path)
    else:
        return str(path.resolve())

# 动态导入
def bimports(*module_paths):
    """从模块导入函数、常量和类，返回字典"""
    contents = {}
    for module_path in module_paths:
        # 导入模块
        # module = importlib.import_module(module_name, module_path)
        module_name = Path(module_path).name
        spec = importlib.util.spec_from_file_location(module_name, module_path)
        module = importlib.util.module_from_spec(spec)
        spec.loader.exec_module(module)

        # 遍历模块所有成员
        for name, obj in inspect.getmembers(module):
            # 跳过特殊属性（以双下划线开头结尾）
            if name.startswith('__') and name.endswith('__'):
                continue
                # 分类处理不同对象类型
            if inspect.isfunction(obj):
                contents[name] = obj
            elif inspect.isclass(obj):
                contents[name] = obj
            elif isinstance(obj, (int, float, str, bool, tuple, list, dict, set)):
                # 假设全大写变量为常量（常见约定）
                if name.isupper():
                    contents[name] = obj
                else:
                    contents[name] = obj
    return contents


import re
import numbers
import inspect

# 单位到米的转换基准表
UNIT_TO_METER = {
    'm': 1,          'meter': 1,       'meters': 1,    '米': 1,
    'cm': 0.01,      'centimeter': 0.01, '厘米': 0.01,  'dm': 0.1, 
    'mm': 0.001,     'millimeter': 0.001, '毫米': 0.001,
    'km': 1000,      'kilometer': 1000, '千米': 1000,
    'inch': 0.0254,  'inches': 0.0254,  '英寸': 0.0254,
    'mm2': 0.000001,  '平方毫米': 0.000001 ,  'km^2': 1000000,   'mm^2': 0.000001,
    'cm^2': 0.0001,   'm^2': 1,    'N/m': 1,     'MPa': 1000000, # 兆帕 (转换为帕)
    'N/mm2': 0.102,  # 牛顿每平方毫米 (1 N/mm² = 0.102 kg/mm²)
    'N/mm²': 0.102,  # 牛顿每平方毫米 (1 N/mm² = 0.102 kg/mm²)
    'kg/mm²': 1,     # 千克力每平方毫米（基准单位）
    'kg/(m·mm²)': 1, # 千克力每米每平方毫米（基准单位）
    'N/(m·mm²)': 0.102, # 牛顿每米每平方毫米 (1 N/(m·mm²) = 0.102 kg/(m·mm²))
    'N/m2': 1,        # 牛顿每平方米 (帕)
    'kN/m': 1000,     # 平方毫米到平方米的转换
    'V': 0.001,    # 1 V = 0.001 kV
    'kV': 1.0,     # 基准单位
    'MV': 1000.0, 
    'N': 1.0,      # 基准单位
    'kN': 1000.0,  # 1 kN = 1000 N
    'MN': 1000000.0,  # 1 MN = 1000000 N
    '牛': 1.0,     # 中文单位
    '千牛': 1000.0, # 中文单位
    'g': 0.001,      'gram': 0.001,    '克': 0.001,
    'kg': 1.0,       'kilogram': 1.0,  '千克': 1.0,
    't': 1000.0,     'ton': 1000.0,    '吨': 1000.0,
    'kg/m': 1.0,       # 基准单位
    'g/m': 0.001,      # 1 g/m = 0.001 kg/m
    't/m': 1000.0,     # 1 t/m = 1000 kg/m
    'N/m': 0.102,      # 1 N/m ≈ 0.102 kg/m（考虑重力加速度的反向转换）
    'kN/m': 102.0,     # 1 kN/m ≈ 102 kg/m
}

# 标准参数单位配置
PARAM_UNITS = {
    '导线直径': 'mm',  # 需要毫米单位的参数
    '跨越架承载索载有效横截面积S': 'mm2', 
    '跨越架承载索载有效横截面积S': 'mm^2', # 承载索横截面积，单位为平方毫米
    '跨越架承载索弹性系数E': 'N/mm2',  # 而不是N/mm2
    '跨越架承载索弹性系数E': 'N/mm^2',
    '跨越架单根承索上导线自重力' :  'N/m',
    '施工线路跨越档两端绝缘子串长度': 'm',
    '跨越架档距': 'm',
    '跨越物至跨越线路邻近杆塔的水平距离': 'm',
    '跨越线路导线水平张力' :'N',
    '被跨线路两边线间水平距离': 'm',
    '保护网长度': 'm',
    '地锚宽度数据': 'm',
    '地锚长度数据': 'm',
    '地锚埋深': 'm',
    '跨越架承载索封网始点': 'm', 
    '跨越架承载索封网终点': 'm', 
    '跨越架有包裹承载索自重力': 'N/m',
    '封网安装初张力H0': 'N',
    '悬挂点高差': 'm',
    '封网安装跨越物对高侧承载索悬点水平距b': 'm',
    '封网安装跨越物对高侧承载索悬点垂距yb': 'm',
    '跨越架承载索破断力': 'kN',
    '跨越架封网器具总重力G': 'N',
    '封网封网封网后张力H2': 'N',
    '封网事故跑线后张力H2': 'N',
    '架空线的比载': 'kg/(m·mm²)',
    '架空线的最低点应力': 'kg/mm²',
    '塔小号侧距离': 'm',
    '放线滑轮内的导线与承载索滑轮内承载索的垂直高差':'m',
    '跨越挡小号侧塔位导线悬挂位置相对于高程基准面的高度':'m',
    '跨越点被跨电力线最高点相对高程基准面的高度':'m',
    '临时横梁_钢抱杆中节_规格_长度':'m',
    '跨越电压等级':'kV',
    '与领塔悬挂点的高差':'m',
    'φ10 强力丝初始挂点张力' :'kg',
    '架空线单位长度自重力':'kg/m',
    '牵引绳索_强力丝_10_破断拉力':'kN',
    '线档档距':'m',
    'φ18 强力丝初始挂点张力' :'kg',
    '牵引绳索_强力丝_18_破断拉力':'kN',
    'φ13 导引绳初始挂点张力' :'kg',
    '牵引绳索_导引绳_13_破断拉力':'kN',
    'φ18 导引绳初始挂点张力' :'kg',
    '牵引绳索_导引绳_18_破断拉力':'kN',
    'φ28 牵引绳初始挂点张力' :'kg',
    '牵引绳索_牵引绳_28_破断拉力':'kN',
}

def convert_value(s, param_name=""):
    """
    将输入值转换为标准单位和数值
    
    Args:
        s: 输入值 (数字或带单位字符串)
        param_name: 参数名称，用于查找预设单位
        
    Returns:
        (数值, 单位) 元组
    
    Examples:
        >>> convert_value("10m", "导线直径")
        (10000.0, 'mm')
        >>> convert_value(15.5, "厚度")
        (15.5, 'mm')
    """
    # 获取目标单位（默认米）
    target_unit = PARAM_UNITS.get(param_name, 'm')
    
    if isinstance(s, numbers.Number):
        return float(s), target_unit
    
    if isinstance(s, str):
        s = s.strip()  # 只去除空格，不转小写
        
        # 提取数值部分
        num_match = re.match(r'^\s*([+-]?\d+\.?\d*)', s)
        if not num_match:
            raise ValueError(f"无效数值格式: '{s}'")
        
        value = float(num_match.group(1))
        unit_str = s[num_match.end():].strip()

        # 修改正则表达式以匹配包含特殊字符的完整单位
        # 例如N/m2, N/mm2, kg/m³等
        unit_match = re.match(r'^([a-zA-Z0-9/\^²³]+[\u4e00-\u9fa5]*)', unit_str)
        src_unit = unit_match.group(0) if unit_match else ""
        
        # 如果单位为空，使用目标单位
        if not src_unit:
            return value, target_unit
        
        # 检查单位有效性
        if src_unit not in UNIT_TO_METER:
            raise ValueError(f"不支持的单位: '{src_unit}'")

        # 转换到目标单位
        value_m = value * UNIT_TO_METER[src_unit]
        converted = value_m / UNIT_TO_METER[target_unit]
        # 直接返回转换后的值，不做round
        return converted, target_unit
    
    raise ValueError(f"不支持的输入类型: {type(s)}")

def convert_params(*args):
    """
    批量转换参数，自动识别调用者参数名称
    
    Returns:
        始终返回包含 (数值, 单位) 元组的元组
    """
    frame = inspect.currentframe().f_back
    param_names = frame.f_code.co_varnames[:frame.f_code.co_argcount] if frame else []
    
    results = []
    for idx, arg in enumerate(args):
        name = param_names[idx] if idx < len(param_names) else ""
        try:
            results.append(convert_value(arg, name))
        except ValueError as e:
            arg_pos = f"第{idx+1}个参数" + (f"({name})" if name else "")
            raise ValueError(f"{arg_pos}转换失败: {str(e)}")
    
    # 始终返回元组，即使只有一个参数
    return tuple(results)

def bfloats_with_units(*args):
    converted = convert_value(*args)
    return tuple(v[0] for v in converted)